package edu.um.token;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import edu.um.variable.VariableType;

/**
 * The token types
 *
 * @author diego
 */
public enum TokenKind {
  BEGIN("begin"),

  END("end"),

  PUNTO("\\."),

  VAR("var"),

  DEFINE_TIPO_DATO(":"),

  OF("of"),

  TIPO_WORD("word", VariableType.WORD),

  TIPO_BYTE("byte", VariableType.BYTE),

  TIPO_STRING_BLANCO("string_blanco", VariableType.STRING_BLANCO),

  TIPO_STRING_SUBRAYADO("string_subrayado", VariableType.STRING_SUBRAYADO),

  TIPO_ARRAY("array", VariableType.ARRAY),

  TIPO_RECORD("record", VariableType.REGISTRO),

  FIN_SENTENCIA(";"),

  ASIGNA_VALOR(":="),

  CONST_BYTE("\\d{1,3}") {
    @Override
    public boolean specificValidation(String value) {
      if ((value.length() > 1 && value.startsWith("0"))
          || Integer.parseInt(value) > 256) {
        return false;
      }
      return true;
    }
  },

  CONST_WORD("\\d{1,6}") {
    @Override
    public boolean specificValidation(String value) {
      if ((value.length() > 1 && value.startsWith("0"))
          || Integer.parseInt(value) > 65535) {
        return false;
      }
      return true;
    }
  },

  STRING_BLANCO("'[a-z][a-z ]*[a-z]'") {
    private final Pattern extraPattern = Pattern.compile("( ){2,}");

    @Override
    public boolean specificValidation(String value) {
      Matcher extraMatcher = extraPattern.matcher(value);
      if (extraMatcher.find()) {
        return false;
      }
      return true;
    }
  },

  STRING_SUBRAYADO("'[a-z][a-z_]*[a-z]'") {
    private final Pattern extraPattern = Pattern.compile("(_){3,}");

    @Override
    public boolean specificValidation(String value) {
      Matcher extraMatcher = extraPattern.matcher(value);
      if (extraMatcher.find()) {
        return false;
      }
      return true;
    }
  },

  READLN("readln"),

  WRITELN("writeln"),

  IF("if"),

  COMPARADOR("=|<>"),

  THEN("then"),

  ELSE("else"),

  OPERADOR_UNARIO("!"),

  OPERADOR("-|\\+|\\*|\\^"),

  ABRE_PARENTESIS("\\("),

  CIERRA_PARENTESIS("\\)"),

  ABRE_CORCHETE("\\["),

  CIERRA_CORCHETE("\\]"),

  COMA("\\,"),

  INTERVALO("\\.\\."),

  ID("[a-z]+");

  /**
   * The matcher
   */
  private Matcher matcher;

  /**
   *
   */
  private VariableType variableType = null;

  /**
   * The constructor
   *
   * @param regex
   */
  TokenKind(String regex) {
    matcher = Pattern.compile(regex).matcher("");
  }

  /**
   * The constructor
   *
   * @param regex
   */
  TokenKind(String regex, VariableType theVariableType) {
    matcher = Pattern.compile(regex).matcher("");
    variableType = theVariableType;
  }

  /**
   * @param candidate the string to be matched
   * @return if the string matches with this kind
   */
  public boolean matches(String candidate) {
    matcher.reset(candidate);
    return matcher.matches();
  }

  /**
   * @param value
   * @return
   */
  public static TokenKind find(String value) {
    for (TokenKind tokenKind : TokenKind.values()) {
      if (tokenKind.accepts(value)) {
        return tokenKind;
      }
    }
    return null;
  }

  /**
   * @param value
   * @return
   */
  public boolean specificValidation(String value) {
    return true;
  }

  public VariableType getVariableType() {
    return variableType;
  }

  public boolean accepts(String value) {
    return (this.matches(value) && this.specificValidation(value));
  }
}
